package com.springboot.example.monitor.test;

import com.springboot.example.monitor.domain.model.ProjectInfo;
import com.springboot.example.monitor.util.DateHelper;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XppDriver;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileWriter;
import java.io.Writer;
import java.lang.reflect.Field;
import java.util.Date;
import java.util.Map;

/**
 * Created by zhangchaohui on 2016/2/15.
 */
public class XmlUtil {


    private static Logger logger = LoggerFactory.getLogger(XmlUtil.class);


    private static XStream xstream = createXstream();
    private static XStream mapXstream = new XStream();//转换map专用xstream，防止map注册转换器导致原xstream无法正常解析

    public static XStream createXstream() {
        return new XStream(new XppDriver() {
            @Override
            public HierarchicalStreamWriter createWriter(Writer out) {
                return new PrettyPrintWriter(out) {
                    boolean cdata = false;
                    Class<?> targetClass = null;

                    @Override
                    public void startNode(String name,
                                          @SuppressWarnings("rawtypes") Class clazz) {
                        super.startNode(name, clazz);
                        //业务处理，对于用XStreamCDATA标记的Field，需要加上CDATA标签
                        if (!name.equals("xml")) {
                            cdata = needCDATA(targetClass, name);
                        } else {
                            targetClass = clazz;
                        }
                    }

                    @Override
                    protected void writeText(QuickWriter writer, String text) {
                        if (cdata) {
                            writer.write(cDATA(text));
                        } else {
                            writer.write(text);
                        }
                    }
                };
            }
        });
    }

    private static String cDATA(String text) {
        return "<![CDATA[" + text + "]]>";
    }

    private static boolean needCDATA(Class<?> targetClass, String fieldAlias) {
        boolean cdata = false;
        //first, scan self
        cdata = existsCDATA(targetClass, fieldAlias);
        //添加内部类是否增加CDATA的判断
        Class[] innerClazz = targetClass.getDeclaredClasses();
        for (Class clazz : innerClazz) {
            cdata = existsCDATA(clazz, fieldAlias);
        }
        //添加内部类是否增加CDATA的判断结束
        if (cdata) return cdata;
        //if cdata is false, scan supperClass until java.lang.Object
        Class<?> superClass = targetClass.getSuperclass();
        while (!superClass.equals(Object.class)) {
            cdata = existsCDATA(superClass, fieldAlias);
            if (cdata) return cdata;
            superClass = superClass.getClass().getSuperclass();
        }
        return false;
    }

    private static boolean existsCDATA(Class<?> clazz, String fieldAlias) {
        //scan fields
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            //1. exists XStreamCDATA
            if (field.getAnnotation(XstreamCDATA.class) != null) {
                XStreamAlias xStreamAlias = field.getAnnotation(XStreamAlias.class);
                //2. exists XStreamAlias
                if (null != xStreamAlias) {
                    if (fieldAlias.equals(xStreamAlias.value()))//matched
                        return true;
                } else {// not exists XStreamAlias
                    if (fieldAlias.equals(field.getName()))
                        return true;
                }
            }
        }
        return false;
    }

    /**
     * 将object转化为xml
     *
     * @param object
     * @return
     */
    public static String marshal(Object object) {
        String result = "";
        try {
            xstream.processAnnotations(object.getClass());
            xstream.alias("xml", object.getClass());
            result = xstream.toXML(object);
        } catch (Exception e) {
            logger.info("将object转化为xml时候报错：" + e.getMessage());
            e.printStackTrace();

        }
        return result;
    }

    /**
     * 将xml转化为object
     */
    public static Object unmarshal(String xml, Object object) {
        xstream.alias("xml", object.getClass());
        xstream.processAnnotations(object.getClass());
        xstream.fromXML(xml, object);
        return object;
    }

    public static Map<String, String> convertToMap(String xml) {
        mapXstream.alias("xml", Map.class);
//        mapXstream.registerConverter(new MapEntryConverter());
        Map<String, String> map = (Map<String, String>) mapXstream.fromXML(xml);

        return map;
    }


    /**
     * 增加logs日志到xml
     *
     * @param info
     * @throws Throwable
     */
    public static void addLogsInfo(ProjectInfo info) throws Throwable {
        String url = XmlUtil.class.getClassLoader().getResource("alert/alert-logs.xml").getPath();
        File myXML = new File(url);
        SAXReader reader = new SAXReader();
        Document document = reader.read(myXML);
        Element root = document.getRootElement();
        Element project = root.addElement("project");
        project.addAttribute("enable", "true");
        project.addAttribute("number", "1");
        Element ip = project.addElement("ip");
        ip.setText(info.getIp());
        Element port = project.addElement("port");
        port.setText(info.getPort());
        Element date = project.addElement("date");
        date.setText(DateHelper.format(new Date(), DateHelper.BOTH));
        Element time = project.addElement("time");
        time.setText(String.valueOf(new Date().getTime()));

        OutputFormat format = OutputFormat.createPrettyPrint();
        format.setEncoding("UTF-8");
        FileWriter newFile = new FileWriter(new File(url));
        XMLWriter newWriter = new XMLWriter(newFile, format);
        newWriter.write(document);
        newWriter.close();
    }


    public static void main(String[] args) {
//        ImageResponseMessage imageResponseMessage = new ImageResponseMessage("123123123");
//        imageResponseMessage.setFromUserName("111");
//        imageResponseMessage.setCreateTime(12312312312L);
//        imageResponseMessage.setMsgType("image");
//        imageResponseMessage.setToUserName("1212");
//        String str = XmlUtil.marshal(imageResponseMessage);
//        System.out.println("str:"+str);
          long a = 1456469386929L;
          long b = new Date().getTime();
          int c = (int)((b - a)/1000/60);
          System.out.println(c);
    }
}
